package sdk

import (
	"errors"

	serialize "chainmaker.org/chainmaker/common/v2/serialize"
)

type StateKeyResultItorator struct {
	s     *SDK
	index int
	keys  []string
}

func newStateKeyResultItorator(s *SDK, keys []string) *StateKeyResultItorator {
	return &StateKeyResultItorator{
		s:     s,
		index: 0,
		keys:  keys,
	}
}

// Next return key,field,value,code
func (si *StateKeyResultItorator) Next() (string, string, []byte, error) {
	if !si.HasNext() {
		return "", "", nil, errors.New("no more data")
	}
	key := si.keys[si.index]
	si.index++
	value, valueErr := si.s.StateMap.Get(key)
	if valueErr != nil {
		return "", "", nil, valueErr
	}
	_, originKey, field := si.s.DeContructKey(key)
	return originKey, field, []byte(value), nil
}

func (si *StateKeyResultItorator) Close() (bool, error) {
	si.index = 0
	return true, nil
}
func (si *StateKeyResultItorator) HasNext() bool {
	return si.index+1 <= len(si.keys)

}

func (si *StateKeyResultItorator) NextRow() (*serialize.EasyCodec, error) {
	key, field, value, err := si.Next()
	if err != nil {
		return nil, err
	}
	ec := serialize.NewEasyCodec()
	ec.AddString(EC_KEY_TYPE_KEY, string(key))
	ec.AddString(EC_KEY_TYPE_FIELD, string(field))
	ec.AddBytes(EC_KEY_TYPE_VALUE, value)
	return ec, nil
}

type HistoryResultItorator struct {
	s      *SDK
	index  int
	values []string
	key    string
	field  string
}

func newHistoryResultItorator(s *SDK, key string, values []string) *HistoryResultItorator {
	_, originalKey, field := s.DeContructKey(key)
	return &HistoryResultItorator{
		s:      s,
		index:  0,
		values: values,
		key:    originalKey,
		field:  field,
	}
}

// Next return key,field,value,code
func (si *HistoryResultItorator) Next() (*KeyModification, error) {
	if !si.HasNext() {
		return nil, errors.New("no more data")
	}
	value := si.values[si.index]
	si.index++
	return &KeyModification{
		Key:         si.key,
		Field:       si.field,
		Value:       []byte(value),
		TxId:        ContractParamTxIdValue,
		BlockHeight: 1,
		IsDelete:    len(value) == 0,
		Timestamp:   ContractParamTxTimeStampValue,
	}, nil
}

func (si *HistoryResultItorator) Close() (bool, error) {
	si.index = 0
	return true, nil
}
func (si *HistoryResultItorator) HasNext() bool {
	return si.index+1 <= len(si.values)

}

func (si *HistoryResultItorator) NextRow() (*serialize.EasyCodec, error) {
	keyHistory, err := si.Next()
	if err != nil {
		return nil, err
	}
	ec := serialize.NewEasyCodec()
	ec.AddBytes(EC_KEY_TYPE_VALUE, keyHistory.Value)
	ec.AddString(EC_KEY_TYPE_TX_ID, string(keyHistory.TxId))
	ec.AddInt32(EC_KEY_TYPE_BLOCK_HEITHT, int32(keyHistory.BlockHeight))

	ec.AddString(EC_KEY_TYPE_TIMESTAMP, keyHistory.Timestamp)

	isDelete := convertFromIsDelete(keyHistory.IsDelete)
	ec.AddInt32(EC_KEY_TYPE_IS_DELETE, isDelete)

	ec.AddString(EC_KEY_TYPE_KEY, keyHistory.Key)
	ec.AddString(EC_KEY_TYPE_FIELD, keyHistory.Field)
	return ec, nil
}

func convertFromIsDelete(isDelete bool) int32 {
	if isDelete {
		return 1
	}
	return 0
}
